{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "04a72c0e",
   "metadata": {},
   "source": [
    "# The Continuous Thought Machine – Tutorial 01: MNIST [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/SakanaAI/continuous-thought-machines/blob/main/examples/01_mnist.ipynb) [![arXiv](https://img.shields.io/badge/arXiv-2505.05522-b31b1b.svg)](https://arxiv.org/abs/2505.05522)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d88fc6d1",
   "metadata": {},
   "source": [
    "Modern deep learning models ignore time as a core computational element. In contrast, the **Continuous Thought Machine (CTM)** introduces internal recurrence and neural synchronization to model *thinking as a temporal process*.\n",
    "\n",
    "### Key Ideas\n",
    "\n",
    "- **Internal Ticks**: The CTM runs over a self-generated temporal axis (independent of input), which we view as a dimension over which thought can unfold.\n",
    "- **Neuron-Level Models**: Each neuron has a private MLP that processes its own history of pre-activations over time.\n",
    "- **Synchronization as Representation**: CTMs compute neuron-to-neuron synchronization over time and use these signals for attention and output.\n",
    "\n",
    "### Why It Matters\n",
    "\n",
    "- Enables **interpretable, dynamic reasoning**\n",
    "- Supports **adaptive compute** (e.g. more ticks for harder tasks)\n",
    "- Works across tasks: classification, reasoning, memory, RL—*without changing the core mechanisms*.\n",
    "\n",
    "----"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b05cf27b",
   "metadata": {},
   "source": [
    "### MNIST Classification\n",
    "\n",
    "In this tutorial we walk through a simple example; training a CTM to classify MNIST digits. We cover:\n",
    "- Defining the model\n",
    "- Constructing the loss function\n",
    "- Training\n",
    "- Building visualization"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c257dbd3",
   "metadata": {},
   "source": [
    "Imports"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "a7bfbfe0",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "from tqdm import tqdm\n",
    "import numpy as np\n",
    "import random\n",
    "from scipy.special import softmax\n",
    "import math\n",
    "from torchvision import datasets, transforms\n",
    "import matplotlib.pyplot as plt\n",
    "from IPython.display import display, clear_output\n",
    "import seaborn as sns\n",
    "import imageio\n",
    "import mediapy\n",
    "\n",
    "import torch._dynamo as dynamo\n",
    "\n",
    "dynamo.config.suppress_errors = False  # Raise errors on fallback"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "97220107",
   "metadata": {},
   "source": [
    "Set the seed for reproducability"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "88b75133",
   "metadata": {},
   "outputs": [],
   "source": [
    "def set_seed(seed=42, deterministic=True):\n",
    "    random.seed(seed)\n",
    "    np.random.seed(seed)\n",
    "    torch.manual_seed(seed)\n",
    "    torch.cuda.manual_seed_all(seed)\n",
    "    torch.backends.cudnn.deterministic = deterministic\n",
    "    torch.backends.cudnn.benchmark = False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "5a9f123b",
   "metadata": {},
   "outputs": [],
   "source": [
    "set_seed(42)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5ee6aa63",
   "metadata": {},
   "source": [
    "We start by defining some helper classes, which we will use in the CTM.\n",
    "\n",
    "Of note is the SuperLinear class, which implements N unique linear transformations. This SuperLinear class will be used for the neuron-level models."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "50c9ac82",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Identity(nn.Module):\n",
    "    \"\"\"Identity Module.\"\"\"\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "\n",
    "    def forward(self, x):\n",
    "        return x\n",
    "\n",
    "class Squeeze(nn.Module):\n",
    "    \"\"\"Squeeze Module.\"\"\"\n",
    "    def __init__(self, dim):\n",
    "        super().__init__()\n",
    "        self.dim = dim\n",
    "\n",
    "    def forward(self, x):\n",
    "        return x.squeeze(self.dim)\n",
    "\n",
    "class SuperLinear(nn.Module):\n",
    "    \"\"\"SuperLinear Layer: Implements Neuron-Level Models (NLMs) for the CTM.\"\"\"\n",
    "    def __init__(self, in_dims, out_dims, N, dropout=0.0):\n",
    "        super().__init__()\n",
    "        self.in_dims = in_dims\n",
    "        self.dropout = nn.Dropout(dropout) if dropout > 0 else Identity()\n",
    "        self.register_parameter('w1', nn.Parameter(\n",
    "            torch.empty((in_dims, out_dims, N)).uniform_(\n",
    "                -1/math.sqrt(in_dims + out_dims),\n",
    "                 1/math.sqrt(in_dims + out_dims)\n",
    "            ), requires_grad=True)\n",
    "        )\n",
    "        self.register_parameter('b1', nn.Parameter(torch.zeros((1, N, out_dims)), requires_grad=True))\n",
    "\n",
    "    def forward(self, x):\n",
    "            out = self.dropout(x)\n",
    "            out = torch.einsum('BDM,MHD->BDH', out, self.w1) + self.b1\n",
    "            out = out.squeeze(-1)\n",
    "            return out"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b0eb50ea",
   "metadata": {},
   "source": [
    "Next, we define a helper function `compute_normalized_entropy`. We will use this function inside the CTM to compute the certainty of the model at each internal tick as `certainty = 1 - normalized entropy`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "4eedd9ee",
   "metadata": {},
   "outputs": [],
   "source": [
    "def compute_normalized_entropy(logits, reduction='mean'):\n",
    "    \"\"\"Computes the normalized entropy for certainty-loss.\"\"\"\n",
    "    preds = F.softmax(logits, dim=-1)\n",
    "    log_preds = torch.log_softmax(logits, dim=-1)\n",
    "    entropy = -torch.sum(preds * log_preds, dim=-1)\n",
    "    num_classes = preds.shape[-1]\n",
    "    max_entropy = torch.log(torch.tensor(num_classes, dtype=torch.float32))\n",
    "    normalized_entropy = entropy / max_entropy\n",
    "    if len(logits.shape)>2 and reduction == 'mean':\n",
    "        normalized_entropy = normalized_entropy.flatten(1).mean(-1)\n",
    "    return normalized_entropy"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f89b70a8",
   "metadata": {},
   "source": [
    "## CTM Architecture Overview\n",
    "\n",
    "The CTM implementation is initialized with the following core parameters:\n",
    "\n",
    "- `iterations`: Number of internal ticks (recurrent steps).\n",
    "- `d_model`: Total number of neurons.\n",
    "- `d_input`: Input and attention embedding dimension.\n",
    "- `memory_length`: Length of the sliding activation window used by each neuron.\n",
    "- `heads`: Number of attention heads.\n",
    "- `n_synch_out`: Number of neurons used for output synchronization.\n",
    "- `n_synch_action`: Number of neurons used for computing attention queries.\n",
    "- `out_dims`: Dimensionality of the model's output.\n",
    "\n",
    "### Key Components\n",
    "\n",
    "Upon initialization, the CTM builds the following modules:\n",
    "\n",
    "- **Backbone**: A CNN feature extractor for the input (e.g. image).\n",
    "- **Synapses**: A communication layer allowing neurons to interact.\n",
    "- **Trace Processor**: A neuron-level model that operates on each neuron's temporal activation trace.\n",
    "- **Synchronization Buffers**: For tracking decay.\n",
    "- **Learned Initial States**: Starting activations and traces for the system.\n",
    "\n",
    "---\n",
    "\n",
    "## Forward Pass Mechanics\n",
    "\n",
    "At each internal tick `stepi`, the CTM executes the following procedure:\n",
    "\n",
    "1. **Initialize recurrent state**:\n",
    "    - `state_trace`: Memory trace per neuron.\n",
    "    - `activated_state`: Current post-activations.\n",
    "    - `decay_alpha_out`, `decay_beta_out`: Values for calculating synchronization.\n",
    "\n",
    "2. **Featurize input**:\n",
    "    - Use the CNN backbone to extract key-value attention pairs `kv`.\n",
    "\n",
    "3. **Internal Loop** (for each tick `stepi`):\n",
    "    1. Compute `synchronisation_action` from `n_synch_action` neurons.\n",
    "    2. Generate attention query `q` from this synchronization.\n",
    "    3. Perform multi-head cross-attention over `kv`.\n",
    "    4. Concatenate attention output with the current neuron activations.\n",
    "    5. Update neurons via the synaptic module.\n",
    "    6. Append new activation to the trace window.\n",
    "    7. Update neuron states using the `trace_processor`.\n",
    "    8. Compute `synchronisation_out` from `n_synch_out` neurons.\n",
    "    9. Project to the output space via `output_projector`.\n",
    "    10. Compute prediction certainty from normalized entropy.\n",
    "\n",
    "This inner loop is repeated for the configured number of internal ticks. The CTM emits **predictions and certainties at every internal tick**.\n",
    "\n",
    "> For detailed mathematical formulation of the synchronization mechanism, please refer to the technical report."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "f357853f",
   "metadata": {},
   "outputs": [],
   "source": [
    "class ContinuousThoughtMachine(nn.Module):\n",
    "    def __init__(self,\n",
    "                 iterations,\n",
    "                 d_model,\n",
    "                 d_input,\n",
    "                 memory_length,\n",
    "                 heads,\n",
    "                 n_synch_out,\n",
    "                 n_synch_action,\n",
    "                 out_dims,\n",
    "                 memory_hidden_dims,\n",
    "                 dropout=0.0\n",
    "                 ):\n",
    "        super(ContinuousThoughtMachine, self).__init__()\n",
    "\n",
    "        # --- Core Parameters ---\n",
    "        self.iterations = iterations\n",
    "        self.d_model = d_model\n",
    "        self.d_input = d_input\n",
    "        self.memory_length = memory_length\n",
    "        self.n_synch_out = n_synch_out\n",
    "        self.n_synch_action = n_synch_action\n",
    "        self.out_dims = out_dims\n",
    "        self.memory_length = memory_length\n",
    "        self.memory_hidden_dims = memory_hidden_dims\n",
    "\n",
    "        # --- Input Processing  ---\n",
    "        self.backbone = nn.Sequential(\n",
    "            nn.LazyConv2d(d_input, kernel_size=3, stride=1, padding=1),\n",
    "            nn.BatchNorm2d(d_input),\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2d(2, 2),\n",
    "            nn.LazyConv2d(d_input, kernel_size=3, stride=1, padding=1),\n",
    "            nn.BatchNorm2d(d_input),\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2d(2, 2),\n",
    "        )\n",
    "        self.attention = nn.MultiheadAttention(self.d_input, heads, dropout, batch_first=True)\n",
    "        self.kv_proj = nn.Sequential(nn.LazyLinear(self.d_input), nn.LayerNorm(self.d_input))\n",
    "        self.q_proj = nn.LazyLinear(self.d_input)\n",
    "\n",
    "        # --- Core CTM Modules ---\n",
    "        self.synapses = nn.Sequential(\n",
    "                nn.Dropout(dropout),\n",
    "                nn.LazyLinear(d_model * 2),\n",
    "                nn.GLU(),\n",
    "                nn.LayerNorm(d_model)\n",
    "            )\n",
    "        self.trace_processor = nn.Sequential(\n",
    "            SuperLinear(in_dims=memory_length, out_dims=2 * memory_hidden_dims, N=d_model, dropout=dropout),\n",
    "            nn.GLU(),\n",
    "            SuperLinear(in_dims=memory_hidden_dims, out_dims=2, N=d_model, dropout=dropout),\n",
    "            nn.GLU(),\n",
    "            Squeeze(-1)\n",
    "        )\n",
    "\n",
    "        #  --- Start States ---\n",
    "        self.register_parameter('start_activated_state', nn.Parameter(\n",
    "                torch.zeros((d_model)).uniform_(-math.sqrt(1/(d_model)), math.sqrt(1/(d_model))),\n",
    "                requires_grad=True\n",
    "            ))\n",
    "\n",
    "        self.register_parameter('start_trace', nn.Parameter(\n",
    "            torch.zeros((d_model, memory_length)).uniform_(-math.sqrt(1/(d_model+memory_length)), math.sqrt(1/(d_model+memory_length))),\n",
    "            requires_grad=True\n",
    "        ))\n",
    "\n",
    "        # --- Synchronisation ---\n",
    "        self.synch_representation_size_action = (self.n_synch_action * (self.n_synch_action+1))//2\n",
    "        self.synch_representation_size_out = (self.n_synch_out * (self.n_synch_out+1))//2\n",
    "\n",
    "        for synch_type, size in [('action', self.synch_representation_size_action), ('out', self.synch_representation_size_out)]:\n",
    "            print(f\"Synch representation size {synch_type}: {size}\")\n",
    "\n",
    "        self.set_synchronisation_parameters('out')\n",
    "        self.set_synchronisation_parameters('action')\n",
    "\n",
    "        # --- Output Procesing ---\n",
    "        self.output_projector = nn.Sequential(nn.LazyLinear(self.out_dims))\n",
    "\n",
    "    def set_synchronisation_parameters(self, synch_type: str):\n",
    "        synch_representation_size = self.synch_representation_size_action if synch_type == 'action' else self.synch_representation_size_out\n",
    "        self.register_parameter(f'decay_params_{synch_type}', nn.Parameter(torch.zeros(synch_representation_size), requires_grad=True))\n",
    "\n",
    "\n",
    "    def compute_synchronisation(self, activated_state, decay_alpha, decay_beta, r, synch_type):\n",
    "        if synch_type == 'action':\n",
    "            n_synch = self.n_synch_action\n",
    "            selected_left = selected_right = activated_state[:, -n_synch:]\n",
    "        elif synch_type == 'out':\n",
    "            n_synch = self.n_synch_out\n",
    "            selected_left = selected_right = activated_state[:, :n_synch]\n",
    "\n",
    "        outer = selected_left.unsqueeze(2) * selected_right.unsqueeze(1)\n",
    "        i, j = torch.triu_indices(n_synch, n_synch)\n",
    "        pairwise_product = outer[:, i, j]\n",
    "\n",
    "        if decay_alpha is None or decay_beta is None:\n",
    "            decay_alpha = pairwise_product\n",
    "            decay_beta = torch.ones_like(pairwise_product)\n",
    "        else:\n",
    "            decay_alpha = r * decay_alpha + pairwise_product\n",
    "            decay_beta = r * decay_beta + 1\n",
    "\n",
    "        synchronisation = decay_alpha / (torch.sqrt(decay_beta))\n",
    "        return synchronisation, decay_alpha, decay_beta\n",
    "\n",
    "    def compute_features(self, x):\n",
    "        input_features = self.backbone(x)\n",
    "        kv = self.kv_proj(input_features.flatten(2).transpose(1, 2))\n",
    "        return kv\n",
    "\n",
    "    def compute_certainty(self, current_prediction):\n",
    "        ne = compute_normalized_entropy(current_prediction)\n",
    "        current_certainty = torch.stack((ne, 1-ne), -1)\n",
    "        return current_certainty\n",
    "\n",
    "    def forward(self, x, track=False):\n",
    "        B = x.size(0)\n",
    "        device = x.device\n",
    "\n",
    "        # --- Tracking Initialization ---\n",
    "        pre_activations_tracking = []\n",
    "        post_activations_tracking = []\n",
    "        synch_out_tracking = []\n",
    "        synch_action_tracking = []\n",
    "        attention_tracking = []\n",
    "\n",
    "        # --- Featurise Input Data ---\n",
    "        kv = self.compute_features(x)\n",
    "\n",
    "        # --- Initialise Recurrent State ---\n",
    "        state_trace = self.start_trace.unsqueeze(0).expand(B, -1, -1) # Shape: (B, H, T)\n",
    "        activated_state = self.start_activated_state.unsqueeze(0).expand(B, -1) # Shape: (B, H)\n",
    "\n",
    "        # --- Storage for outputs per iteration\n",
    "        predictions = torch.empty(B, self.out_dims, self.iterations, device=device, dtype=x.dtype)\n",
    "        certainties = torch.empty(B, 2, self.iterations, device=device, dtype=x.dtype)\n",
    "\n",
    "        decay_alpha_action, decay_beta_action = None, None\n",
    "        r_action, r_out = torch.exp(-self.decay_params_action).unsqueeze(0).repeat(B, 1), torch.exp(-self.decay_params_out).unsqueeze(0).repeat(B, 1)\n",
    "\n",
    "        _, decay_alpha_out, decay_beta_out = self.compute_synchronisation(activated_state, None, None, r_out, synch_type='out')\n",
    "\n",
    "        # --- Recurrent Loop  ---\n",
    "        for stepi in range(self.iterations):\n",
    "\n",
    "            # --- Calculate Synchronisation for Input Data Interaction ---\n",
    "            synchronisation_action, decay_alpha_action, decay_beta_action = self.compute_synchronisation(activated_state, decay_alpha_action, decay_beta_action, r_action, synch_type='action')\n",
    "\n",
    "            # --- Interact with Data via Attention ---\n",
    "            q = self.q_proj(synchronisation_action).unsqueeze(1)\n",
    "            attn_out, attn_weights = self.attention(q, kv, kv, average_attn_weights=False, need_weights=True)\n",
    "            attn_out = attn_out.squeeze(1)\n",
    "            pre_synapse_input = torch.concatenate((attn_out, activated_state), dim=-1)\n",
    "\n",
    "            # --- Apply Synapses ---\n",
    "            state = self.synapses(pre_synapse_input)\n",
    "            state_trace = torch.cat((state_trace[:, :, 1:], state.unsqueeze(-1)), dim=-1)\n",
    "\n",
    "            # --- Activate ---\n",
    "            activated_state = self.trace_processor(state_trace)\n",
    "\n",
    "            # --- Calculate Synchronisation for Output Predictions ---\n",
    "            synchronisation_out, decay_alpha_out, decay_beta_out = self.compute_synchronisation(activated_state, decay_alpha_out, decay_beta_out, r_out, synch_type='out')\n",
    "\n",
    "            # --- Get Predictions and Certainties ---\n",
    "            current_prediction = self.output_projector(synchronisation_out)\n",
    "            current_certainty = self.compute_certainty(current_prediction)\n",
    "\n",
    "            predictions[..., stepi] = current_prediction\n",
    "            certainties[..., stepi] = current_certainty\n",
    "\n",
    "            # --- Tracking ---\n",
    "            if track:\n",
    "                pre_activations_tracking.append(state_trace[:,:,-1].detach().cpu().numpy())\n",
    "                post_activations_tracking.append(activated_state.detach().cpu().numpy())\n",
    "                attention_tracking.append(attn_weights.detach().cpu().numpy())\n",
    "                synch_out_tracking.append(synchronisation_out.detach().cpu().numpy())\n",
    "                synch_action_tracking.append(synchronisation_action.detach().cpu().numpy())\n",
    "\n",
    "        # --- Return Values ---\n",
    "        if track:\n",
    "            return predictions, certainties, (np.array(synch_out_tracking), np.array(synch_action_tracking)), np.array(pre_activations_tracking), np.array(post_activations_tracking), np.array(attention_tracking)\n",
    "        return predictions, certainties, synchronisation_out"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a049b6a",
   "metadata": {},
   "source": [
    "## Certainty-Based Loss Function\n",
    "\n",
    "The CTM produces outputs at each internal tick, so the question arises: **how do we optimize the model across this internal temporal dimension?**\n",
    "\n",
    "Our answer is a simple but effective **certainty-based loss** that encourages the model to reason meaningfully across time. Instead of relying on the final tick alone, we aggregate loss from two key internal ticks:\n",
    "\n",
    "1. The tick where the **prediction loss** is lowest.\n",
    "2. The tick where the **certainty** (1 - normalized entropy) is highest.\n",
    "\n",
    "We then take the **average of the losses** at these two points.\n",
    "\n",
    "This approach encourages the CTM to both make accurate predictions and express high confidence in them—while supporting adaptive, interpretable computation over time.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "0f463eb9",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_loss(predictions, certainties, targets, use_most_certain=True):\n",
    "    \"\"\"use_most_certain will select either the most certain point or the final point.\"\"\"\n",
    "\n",
    "    losses = nn.CrossEntropyLoss(reduction='none')(predictions,\n",
    "                                                   torch.repeat_interleave(targets.unsqueeze(-1), predictions.size(-1), -1))\n",
    "\n",
    "    loss_index_1 = losses.argmin(dim=1)\n",
    "    loss_index_2 = certainties[:,1].argmax(-1)\n",
    "    if not use_most_certain:\n",
    "        loss_index_2[:] = -1\n",
    "\n",
    "    batch_indexer = torch.arange(predictions.size(0), device=predictions.device)\n",
    "    loss_minimum_ce = losses[batch_indexer, loss_index_1].mean()\n",
    "    loss_selected = losses[batch_indexer, loss_index_2].mean()\n",
    "\n",
    "    loss = (loss_minimum_ce + loss_selected)/2\n",
    "    return loss, loss_index_2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "e54afe0f",
   "metadata": {},
   "outputs": [],
   "source": [
    "def calculate_accuracy(predictions, targets, where_most_certain):\n",
    "    \"\"\"Calculate the accuracy based on the prediction at the most certain internal tick.\"\"\"\n",
    "    B = predictions.size(0)\n",
    "    device = predictions.device\n",
    "\n",
    "    predictions_at_most_certain_internal_tick = predictions.argmax(1)[torch.arange(B, device=device), where_most_certain].detach().cpu().numpy()\n",
    "    accuracy = (targets.detach().cpu().numpy() == predictions_at_most_certain_internal_tick).mean()\n",
    "\n",
    "    return accuracy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "c1371279",
   "metadata": {},
   "outputs": [],
   "source": [
    "def prepare_data():\n",
    "    transform = transforms.Compose([\n",
    "        transforms.RandomAffine(degrees=15, translate=(0.1, 0.1), scale=(0.9, 1.1)),\n",
    "        transforms.RandomRotation(10),\n",
    "        transforms.ToTensor(),\n",
    "        transforms.Normalize((0.1307,), (0.3081,))\n",
    "    ])\n",
    "    train_data = datasets.MNIST(root=\"./data\", train=True, download=True, transform=transform)\n",
    "    test_data = datasets.MNIST(root=\"./data\", train=False, download=True, transform=transform)\n",
    "    trainloader = torch.utils.data.DataLoader(train_data, batch_size=256, shuffle=True, num_workers=1)\n",
    "    testloader = torch.utils.data.DataLoader(test_data, batch_size=256, shuffle=True, num_workers=1, drop_last=False)\n",
    "    return trainloader, testloader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "2e3fc4d7",
   "metadata": {},
   "outputs": [],
   "source": [
    "def update_training_curve_plot(fig, ax1, ax2, train_losses, test_losses, train_accuracies, test_accuracies, steps):\n",
    "    clear_output(wait=True)\n",
    "    \n",
    "    # Plot loss\n",
    "    ax1.clear()\n",
    "    ax1.plot(range(len(train_losses)), train_losses, 'b-', alpha=0.7, label=f'Train Loss: {train_losses[-1]:.3f}')\n",
    "    ax1.plot(steps, test_losses, 'r-', marker='o', label=f'Test Loss: {test_losses[-1]:.3f}')\n",
    "    ax1.set_title('Loss')\n",
    "    ax1.set_xlabel('Step')\n",
    "    ax1.set_ylabel('Loss')\n",
    "    ax1.legend()\n",
    "    ax1.grid(True, alpha=0.3)\n",
    "\n",
    "    # Plot accuracy\n",
    "    ax2.clear()\n",
    "    ax2.plot(range(len(train_accuracies)), train_accuracies, 'b-', alpha=0.7, label=f'Train Accuracy: {train_accuracies[-1]:.3f}')\n",
    "    ax2.plot(steps, test_accuracies, 'r-', marker='o', label=f'Test Accuracy: {test_accuracies[-1]:.3f}')\n",
    "    ax2.set_title('Accuracy')\n",
    "    ax2.set_xlabel('Step')\n",
    "    ax2.set_ylabel('Accuracy')\n",
    "    ax2.legend()\n",
    "    ax2.grid(True, alpha=0.3)\n",
    "\n",
    "    plt.tight_layout()\n",
    "    display(fig)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "a492b058",
   "metadata": {},
   "outputs": [],
   "source": [
    "def train(model, trainloader, testloader, iterations, test_every, device):\n",
    "\n",
    "  optimizer = torch.optim.AdamW(params=list(model.parameters()), lr=0.0001, eps=1e-8)\n",
    "  iterator = iter(trainloader)\n",
    "  model.train()\n",
    "  \n",
    "  train_losses = []\n",
    "  test_losses = []\n",
    "  train_accuracies = []\n",
    "  test_accuracies = []\n",
    "  steps = []\n",
    "\n",
    "  plt.ion()\n",
    "  fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))\n",
    "\n",
    "  with tqdm(total=iterations, initial=0, dynamic_ncols=True) as pbar:\n",
    "      test_loss = None\n",
    "      test_accuracy = None\n",
    "      for stepi in range(iterations):\n",
    "\n",
    "          try:\n",
    "              inputs, targets = next(iterator)\n",
    "          except StopIteration:\n",
    "              iterator = iter(trainloader)\n",
    "              inputs, targets = next(iterator)\n",
    "          inputs, targets = inputs.to(device), targets.to(device)\n",
    "          predictions, certainties, _ = model(inputs, track=False)\n",
    "          train_loss, where_most_certain = get_loss(predictions, certainties, targets)\n",
    "          train_accuracy = calculate_accuracy(predictions, targets, where_most_certain)\n",
    "\n",
    "          train_losses.append(train_loss.item())\n",
    "          train_accuracies.append(train_accuracy)\n",
    "\n",
    "          train_loss.backward()\n",
    "          optimizer.step()\n",
    "          optimizer.zero_grad()\n",
    "\n",
    "\n",
    "          if stepi % test_every == 0 or stepi == iterations - 1:\n",
    "            model.eval()\n",
    "            with torch.inference_mode():\n",
    "                all_test_predictions = []\n",
    "                all_test_targets = []\n",
    "                all_test_where_most_certain = []\n",
    "                all_test_losses = []\n",
    "\n",
    "                for inputs, targets in testloader:\n",
    "                    inputs, targets = inputs.to(device), targets.to(device)\n",
    "                    predictions, certainties, _ = model(inputs, track=False)\n",
    "                    test_loss, where_most_certain = get_loss(predictions, certainties, targets)\n",
    "                    all_test_losses.append(test_loss.item())\n",
    "\n",
    "                    all_test_predictions.append(predictions)\n",
    "                    all_test_targets.append(targets)\n",
    "                    all_test_where_most_certain.append(where_most_certain)\n",
    "\n",
    "                all_test_predictions = torch.cat(all_test_predictions, dim=0)\n",
    "                all_test_targets = torch.cat(all_test_targets, dim=0)\n",
    "                all_test_where_most_certain = torch.cat(all_test_where_most_certain, dim=0)\n",
    "\n",
    "                test_accuracy = calculate_accuracy(all_test_predictions, all_test_targets, all_test_where_most_certain)\n",
    "                test_loss = sum(all_test_losses) / len(all_test_losses)\n",
    "\n",
    "                test_losses.append(test_loss)\n",
    "                test_accuracies.append(test_accuracy)\n",
    "                steps.append(stepi)\n",
    "            model.train()\n",
    "\n",
    "            update_training_curve_plot(fig, ax1, ax2, train_losses, test_losses, train_accuracies, test_accuracies, steps)\n",
    "\n",
    "          pbar.set_description(f'Train Loss: {train_loss:.3f}, Train Accuracy: {train_accuracy:.3f} Test Loss: {test_loss:.3f}, Test Accuracy: {test_accuracy:.3f}')\n",
    "          pbar.update(1)\n",
    "\n",
    "  plt.ioff()\n",
    "  plt.close(fig)\n",
    "  return model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "2d1658a9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Synch representation size action: 136\n",
      "Synch representation size out: 136\n",
      "Model parameters: 343,658\n"
     ]
    }
   ],
   "source": [
    "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
    "\n",
    "trainloader, testloader = prepare_data()\n",
    "\n",
    "model = ContinuousThoughtMachine(\n",
    "    iterations=15,\n",
    "    d_model=128,\n",
    "    d_input=128,\n",
    "    memory_length=10,\n",
    "    heads=2,\n",
    "    n_synch_out=16,\n",
    "    n_synch_action=16,\n",
    "    memory_hidden_dims=8,\n",
    "    out_dims=10,\n",
    "    dropout=0.0\n",
    ").to(device)\n",
    "\n",
    "sample_batch = next(iter(trainloader))\n",
    "dummy_input = sample_batch[0][:1].to(device)\n",
    "with torch.no_grad():\n",
    "    _ = model(dummy_input)\n",
    "\n",
    "# Now compile the model\n",
    "model = torch.compile(model)\n",
    "\n",
    "def clamp_decay_params(module, _input):\n",
    "    with torch.no_grad():\n",
    "        module.decay_params_action.data.clamp_(0, 15)\n",
    "        module.decay_params_out.data.clamp_(0, 15)\n",
    "\n",
    "model.register_forward_pre_hook(clamp_decay_params)\n",
    "\n",
    "print(f'Model parameters: {sum(p.numel() for p in model.parameters()):,}')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "ce6d7f20",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAGGCAYAAACqvTJ0AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAA4JFJREFUeJzs3Xd4k9XbB/Dvk450t3RPKHvLBpnCy1aRIYLoT4YCDlCwziobtQqCBUFREHCAoAiIighUEBBkisiWDd2ldNKmI8/7x2nSpk3atGQ07fdzXbmSZ5+cFvrkzn3uI8myLIOIiIiIiIiIiMiCFNZuABERERERERER1T4MShERERERERERkcUxKEVERERERERERBbHoBQREREREREREVkcg1JERERERERERGRxDEoREREREREREZHFMShFREREREREREQWx6AUERERERERERFZHINSRERERERERERkcQxKERERERERERGRxTEoRUQ1xtq1ayFJEo4dO2btphARERGZ3SeffAJJktClSxdrN4WIqEoYlCIiIiIiIrJB69atQ3h4OI4cOYJLly5ZuzlERJXGoBQREREREZGNuXr1Kg4ePIjFixfDz88P69ats3aT9MrOzrZ2E4ioGmNQiohqlb///huDBw+Gh4cH3Nzc0LdvX/z11186++Tn52Pu3Llo3LgxnJyc4OPjgx49emDXrl3afRISEjBhwgSEhoZCqVQiKCgIQ4cOxbVr1yz8joiIiKg2WrduHerUqYOHHnoII0eO1BuUSktLw8svv4zw8HAolUqEhoZi7NixSElJ0e6Tm5uLOXPmoEmTJnByckJQUBBGjBiBy5cvAwD27t0LSZKwd+9enXNfu3YNkiRh7dq12nXjx4+Hm5sbLl++jAcffBDu7u548sknAQD79+/HY489hrp160KpVCIsLAwvv/wycnJyyrT7/PnzGDVqFPz8/ODs7IymTZvi7bffBgDs2bMHkiRhy5YtZY5bv349JEnCoUOHKt2fRGQd9tZuABGRpZw5cwY9e/aEh4cHXn/9dTg4OOCzzz5D79698ccff2jrMcyZMwdRUVGYOHEiOnfujIyMDBw7dgwnTpxA//79AQCPPvoozpw5gxdffBHh4eFISkrCrl27cOPGDYSHh1vxXRIREVFtsG7dOowYMQKOjo4YM2YMPv30Uxw9ehSdOnUCAGRlZaFnz544d+4cnn76abRv3x4pKSnYtm0bbt26BV9fXxQWFuLhhx9GTEwMHn/8cUybNg2ZmZnYtWsXTp8+jYYNG1a6XQUFBRg4cCB69OiBDz/8EC4uLgCA77//Hnfv3sXzzz8PHx8fHDlyBB9//DFu3bqF77//Xnv8qVOn0LNnTzg4OGDy5MkIDw/H5cuX8dNPP+Hdd99F7969ERYWhnXr1mH48OFl+qRhw4bo2rXrPfQsEVmUTERUQ6xZs0YGIB89elTv9mHDhsmOjo7y5cuXtevi4uJkd3d3uVevXtp1bdq0kR966CGD17lz544MQF64cKHpGk9ERERkpGPHjskA5F27dsmyLMtqtVoODQ2Vp02bpt1n1qxZMgB58+bNZY5Xq9WyLMvy6tWrZQDy4sWLDe6zZ88eGYC8Z88ene1Xr16VAchr1qzRrhs3bpwMQH7zzTfLnO/u3btl1kVFRcmSJMnXr1/XruvVq5fs7u6us65ke2RZliMjI2WlUimnpaVp1yUlJcn29vby7Nmzy1yHiKovDt8jolqhsLAQO3fuxLBhw9CgQQPt+qCgIDzxxBM4cOAAMjIyAABeXl44c+YM/vvvP73ncnZ2hqOjI/bu3Ys7d+5YpP1EREREGuvWrUNAQAD69OkDAJAkCaNHj8aGDRtQWFgIAPjhhx/Qpk2bMtlEmv01+/j6+uLFF180uE9VPP/882XWOTs7a19nZ2cjJSUF3bp1gyzL+PvvvwEAycnJ2LdvH55++mnUrVvXYHvGjh0LlUqFTZs2addt3LgRBQUF+N///lfldhOR5TEoRUS1QnJyMu7evYumTZuW2da8eXOo1WrcvHkTADBv3jykpaWhSZMmaN26NV577TWcOnVKu79SqcQHH3yAX3/9FQEBAejVqxcWLFiAhIQEi70fIiIiqp0KCwuxYcMG9OnTB1evXsWlS5dw6dIldOnSBYmJiYiJiQEAXL58Ga1atSr3XJcvX0bTpk1hb2+6qi729vYIDQ0ts/7GjRsYP348vL294ebmBj8/PzzwwAMAgPT0dADAlStXAKDCdjdr1gydOnXSqaO1bt063H///WjUqJGp3goRWQCDUkREpfTq1QuXL1/G6tWr0apVK6xatQrt27fHqlWrtPtMnz4dFy9eRFRUFJycnDBz5kw0b95c+00fERERkTn8/vvviI+Px4YNG9C4cWPtY9SoUQBg8ln4DGVMaTKySlMqlVAoFGX27d+/P3755Re88cYb2Lp1K3bt2qUtkq5WqyvdrrFjx+KPP/7ArVu3cPnyZfz111/MkiKyQSx0TkS1gp+fH1xcXHDhwoUy286fPw+FQoGwsDDtOm9vb0yYMAETJkxAVlYWevXqhTlz5mDixInafRo2bIhXXnkFr7zyCv777z+0bdsWixYtwjfffGOR90RERES1z7p16+Dv74/ly5eX2bZ582Zs2bIFK1asQMOGDXH69Olyz9WwYUMcPnwY+fn5cHBw0LtPnTp1AIiZ/Eq6fv260W3+999/cfHiRXz55ZcYO3asdn3JmY0BaEssVNRuAHj88ccRERGBb7/9Fjk5OXBwcMDo0aONbhMRVQ/MlCKiWsHOzg4DBgzAjz/+iGvXrmnXJyYmYv369ejRowc8PDwAALdv39Y51s3NDY0aNYJKpQIA3L17F7m5uTr7NGzYEO7u7tp9iIiIiEwtJycHmzdvxsMPP4yRI0eWeUydOhWZmZnYtm0bHn30Ufzzzz/YsmVLmfPIsgxAzCackpKCZcuWGdynXr16sLOzw759+3S2f/LJJ0a3287OTuecmtdLlizR2c/Pzw+9evXC6tWrcePGDb3t0fD19cXgwYPxzTffYN26dRg0aBB8fX2NbhMRVQ/MlCKiGmf16tXYsWNHmfVz5szBrl270KNHD7zwwguwt7fHZ599BpVKhQULFmj3a9GiBXr37o0OHTrA29sbx44dw6ZNmzB16lQAwMWLF9G3b1+MGjUKLVq0gL29PbZs2YLExEQ8/vjjFnufREREVLts27YNmZmZeOSRR/Ruv//+++Hn54d169Zh/fr12LRpEx577DE8/fTT6NChA1JTU7Ft2zasWLECbdq0wdixY/HVV18hIiICR44cQc+ePZGdnY3du3fjhRdewNChQ+Hp6YnHHnsMH3/8MSRJQsOGDfHzzz8jKSnJ6HY3a9YMDRs2xKuvvorY2Fh4eHjghx9+0DthzNKlS9GjRw+0b98ekydPRv369XHt2jX88ssvOHnypM6+Y8eOxciRIwEA8+fPN74jiaj6sObUf0REprRmzRoZgMHHzZs35RMnTsgDBw6U3dzcZBcXF7lPnz7ywYMHdc7zzjvvyJ07d5a9vLxkZ2dnuVmzZvK7774r5+XlybIsyykpKfKUKVPkZs2aya6urrKnp6fcpUsX+bvvvrPG2yYiIqJaYsiQIbKTk5OcnZ1tcJ/x48fLDg4OckpKinz79m156tSpckhIiOzo6CiHhobK48aNk1NSUrT73717V3777bfl+vXryw4ODnJgYKA8cuRI+fLly9p9kpOT5UcffVR2cXGR69SpIz/77LPy6dOnZQDymjVrtPuNGzdOdnV11duus2fPyv369ZPd3NxkX19fedKkSfI///xT5hyyLMunT5+Whw8fLnt5eclOTk5y06ZN5ZkzZ5Y5p0qlkuvUqSN7enrKOTk5RvYiEVUnkiyXyoMkIiIiIiIiquYKCgoQHByMIUOG4IsvvrB2c4ioClhTioiIiIiIiGzO1q1bkZycrFM8nYhsCzOliIiIiIiIyGYcPnwYp06dwvz58+Hr64sTJ05Yu0lEVEXMlCIiIiIiIiKb8emnn+L555+Hv78/vvrqK2s3h4juATOliIiIiIiIiIjI4pgpRUREREREREREFsegFBERERERERERWZy9tRtgaWq1GnFxcXB3d4ckSdZuDhEREVVzmkoHHh4etfregfdQREREZCxZlpGZmYng4GAoFIbzoWpdUCouLg5hYWHWbgYRERHZmPT0dHh4eFi7GVbDeygiIiKqrJs3byI0NNTg9loXlHJ3dwcgOsYcN5ZqtRrJycnw8/MrNxpI5sH+ty72v/Ww762L/W9d5u7/jIwMBmPAe6iajH1vXex/62L/Ww/73rosdf+kuX8wpNYFpTTp5h4eHma7ocrNzYWHhwf/YVkB+9+62P/Ww763Lva/dbH/LYP3UDUX+9662P/Wxf63Hva9dVmq/ysa8s+fPBERERERERERWRyDUkREREREREREZHEMShERERERERERkcXVuppSRERUPRQWFiI/P9/azTAJtVqN/Px85ObmsiaCFdxr/zs4OMDOzs4MLSMiIiKi8jAoRUREFiXLMhISEpCWlmbtppiMLMtQq9XIzMyssJgjmZ4p+t/LywuBgYH8+RERERFZEINSRERkUZqAlL+/P1xcXGpEEECWZRQUFMDe3r5GvB9bcy/9L8sy7t69i6SkJABAUFCQOZpIRERERHowKGVKhYXAH3/A6cIFoGlT4IEHAA4HICLSKiws1AakfHx8rN0ck2FQyrrutf+dnZ0BAElJSfD39+dQPiIiIiILYeELU9m8GQgPh6JvX3i98AIU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XVaWcftpZt5DSAhKxteM/PKWiIiIzIyZUhagUIiaUgCYKUVERET3LCIiAuPGjUPHjh3RuXNnREdHIzs7GxMmTAAAjB07FiEhIYiKigIADBkyBIsXL0a7du20w/dmzpyJIUOGaINTtiQvz7j9fEoEpRwdgaLuYFCKiIiommBQygKcnYEEZkoRERGRiYwePRrJycmYNWsWEhIS0LZtW+zYsUNb/PzGjRs6mVEzZsyAJEmYMWMGYmNj4efnhyFDhuDdd9+11lu4J3fvGrdfx6BY4AaAEHEf1qqV+dpERERElceglAUMHgy881NRplRCAlBYCNjgt5JERERUfUydOhVTp07Vu23v3r06y/b29pg9ezZmz55tgZaZnzFlKl58EfB9vThTioiIiKof1pSyAA8PIE0ZgEIoREAqKcnaTSIiIiKyWcYUOVerUVw2gUEpIiKiaolBKQuQJEAt2SFNWTQjDutKEREREZmVlKcCUlLEAoNSRERE1RKDUhbEGfiIiIiI7t3hwxXv45hSdL+lVALe3uZtEBEREVUJg1IWoEkx5wx8RERERPfuzJmK92niWmLonjHj/YiIiMjiWOjcAjT3QcyUIiIiIjKvL74AkpOBkNOsJ0VERFTdMVPKAjQT7TFTioiIiMi8/P2Bli0B3LolVjAoRUREVG0xKGUBdeqIZ2ZKEREREZnP9OklFjRfAoaGWqMpREREZAQGpSyImVJERERE5mFvD/TtW2JFLIfvERERVXcMSlkQM6WIiIiIzOPVV0utYFCKiIio2mNQyoJuK4sypVJTgZwc6zaGiIiIqAZp0KDUCgaliIiIqj0GpSwo28ELKoWzWIiPt25jiIiIiGoQzWzHAABZLs5MZ1CKiIio2mJQypIkqXgIH+tKEREREVXaP//oX68oeVebkgLk5YnXQUFmbxMRERFVDYNSFqYtds66UkRERESVNmOGETtpvvzz9wccHc3aHiIiIqo6BqUsjJlSRERERKanM3yP9aSIiIhsAoNSFtKwoXjO92OmFBEREZGpMShFRERkexiUspDLl8XztXxmShERERGZ1a1b4plBKSIiomqNQSkLu62pKcWgFBEREZHJ6BQ619xnhYZapS1ERERkHAalLCxVU1OKw/eIiIiIKiUz08gdOXyPiIjIJjAoZWG3lSUypWTZuo0hIiIisiFffGHkjgxKERER2QQG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TJ482drNqLYMTux85w6Qmytea77cIyIiIptSpaDUl19+iVWrVuGRRx7RrrvvvvsQEhKCF154gUGpcvTsCZTK3heUSsDXF0hJEanoDEoRERHVeDk5OVi6dClCmOljkM5sxSVphu55ewPOzhZrDxEREZlOlYJSqampaNasWZn1zZo1Q2pq6j03qiYr954zJKQ4KHXffRZrExEREZlfnTp1dAqdy7KMzMxMuLi44JtvvrFiy2yUJigVGmrddhAREVGVVSko1aZNGyxbtgxLly7VWb9s2TLcx2BK1YWEAP/8w2LnRERENdBHH32kE5RSKBTw8/NDly5dUKdOHSu2zEaxyDkREZHNq1JQasGCBXjooYewe/dudO3aFQBw6NAh3Lx5E9u3bzdpA2uacrPLNfUQNDdZREREVGOMHz/e2k2oWRiUIiIisnlVmibvgQcewMWLFzF8+HCkpaUhLS0NI0aMwJkzZ/D111+buo01SrmT6mluqpgpRUREVOOsWbMG33//fZn133//Pb788ksrtMjGMShFRERk86oUlAKA4OBgvPvuu/jhhx/www8/4J133sGdO3fwxRdfmLJ9tQszpYiIiGqsqKgo+Pr6llnv7++P9957zwotsnEMShEREdm8KgelyAyYKUVERFRj3bhxA/Xr1y+zvl69erhx44YVWmTjGJQiIiKyeQxKVSfMlCIiIqqx/P39cerUqTLr//nnH/j4+FihRTaOQSkiIiKbx6BUdaK5qUpKAvLzrdsWIiIiMqkxY8bgpZdewp49e1BYWIjCwkL8/vvvmDZtGh5//HFrN8+2qFRAcrJ4zaAUERGRzarU7HsjRowod3taWlqlLr5v3z4sXLgQx48fR3x8PLZs2YJhw4aVe8zevXsRERGBM2fOICwsDDNmzKg5s9n4+gIODiIglZAAhIVZu0VERERkIvPnz8e1a9fQt29f2NuLWzC1Wo2xY8eyplRlaUodKJUAs8yIiIhsVqWCUp6enhVuHzt2rNHny87ORps2bfD0009XGPACgKtXr+Khhx7Cc889h3Xr1iEmJgYTJ05EUFAQBg4caPR1qy2FAggKAm7cEDdbDEoRERHVGI6Ojti4cSPeeecdnDx5Es7OzmjdujXq1atn7abZHs3QveDgCqY2JiIiouqsUkGpNWvWmPTigwcPxuDBg43ef8WKFahfvz4WLVoEAGje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",
      "text/plain": [
       "<Figure size 1200x400 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Train Loss: 0.075, Train Accuracy: 0.969 Test Loss: 0.080, Test Accuracy: 0.968: 100%|██████████| 10000/10000 [35:10<00:00,  4.74it/s]\n"
     ]
    }
   ],
   "source": [
    "model = train(model=model, trainloader=trainloader, testloader=testloader, iterations=10000, test_every=500, device=device)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "af7e308f",
   "metadata": {},
   "source": [
    "## Visualizing CTM Dynamics\n",
    "\n",
    "We define a function to create GIFs that show how the CTMs dynamics. These visualizations include:\n",
    "\n",
    "- **Neuron activations** at each internal tick  \n",
    "- **Attention patterns** across the input  \n",
    "- **Predictions and certainty** at every step"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b3fbae96",
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_gif(predictions, certainties, targets, pre_activations, post_activations, attention, inputs_to_model, filename):\n",
    "    def reshape_attention_weights(attention, target_size=28):\n",
    "        # The num_positions will not be a perfect square if the input size is not a perfect square. If d_input is not a perfect sqaure, interpolate\n",
    "        T, B, num_heads, _, num_positions = attention.shape\n",
    "        attention = torch.tensor(attention, dtype=torch.float32).mean(dim=2).squeeze(2)\n",
    "        height = int(num_positions**0.5)\n",
    "        while num_positions % height != 0: height -= 1\n",
    "        width = num_positions // height\n",
    "        attention = attention.view(T, B, height, width)\n",
    "        return F.interpolate(attention, size=(target_size, target_size), mode='bilinear', align_corners=False)\n",
    "\n",
    "    batch_index = 0\n",
    "    n_neurons_to_visualise = 16\n",
    "    figscale = 0.28\n",
    "    n_steps = len(pre_activations)\n",
    "    heCTMap_cmap = sns.color_palette(\"viridis\", as_cmap=True)\n",
    "    frames = []\n",
    "\n",
    "    attention = reshape_attention_weights(attention)\n",
    "\n",
    "    these_pre_acts = pre_activations[:, batch_index, :]\n",
    "    these_post_acts = post_activations[:, batch_index, :]\n",
    "    these_inputs = inputs_to_model[batch_index,:, :, :]\n",
    "    these_attention_weights = attention[:, batch_index, :, :]\n",
    "    these_predictions = predictions[batch_index, :, :]\n",
    "    these_certainties = certainties[batch_index, :, :]\n",
    "    this_target = targets[batch_index]\n",
    "\n",
    "    class_labels = [str(i) for i in range(these_predictions.shape[0])]\n",
    "\n",
    "    mosaic = [['img_data', 'img_data', 'attention', 'attention', 'probs', 'probs', 'probs', 'probs'] for _ in range(2)] + \\\n",
    "             [['img_data', 'img_data', 'attention', 'attention', 'probs', 'probs', 'probs', 'probs'] for _ in range(2)] + \\\n",
    "             [['certainty'] * 8] + \\\n",
    "             [[f'trace_{ti}'] * 8 for ti in range(n_neurons_to_visualise)]\n",
    "\n",
    "    for stepi in tqdm(range(n_steps), desc=\"Processing steps\", unit=\"step\"):\n",
    "        fig_gif, axes_gif = plt.subplot_mosaic(mosaic=mosaic, figsize=(31*figscale*8/4, 76*figscale))\n",
    "        probs = softmax(these_predictions[:, stepi])\n",
    "        colors = [('g' if i == this_target else 'b') for i in range(len(probs))]\n",
    "\n",
    "        axes_gif['probs'].bar(np.arange(len(probs)), probs, color=colors, width=0.9, alpha=0.5)\n",
    "        axes_gif['probs'].set_title('Probabilities')\n",
    "        axes_gif['probs'].set_xticks(np.arange(len(probs)))\n",
    "        axes_gif['probs'].set_xticklabels(class_labels, fontsize=24)\n",
    "        axes_gif['probs'].set_yticks([])\n",
    "        axes_gif['probs'].tick_params(left=False, bottom=False)\n",
    "        axes_gif['probs'].set_ylim([0, 1])\n",
    "        for spine in axes_gif['probs'].spines.values():\n",
    "            spine.set_visible(False)\n",
    "        axes_gif['probs'].tick_params(left=False, bottom=False)\n",
    "        axes_gif['probs'].spines['top'].set_visible(False)\n",
    "        axes_gif['probs'].spines['right'].set_visible(False)\n",
    "        axes_gif['probs'].spines['left'].set_visible(False)\n",
    "        axes_gif['probs'].spines['bottom'].set_visible(False)\n",
    "\n",
    "        # Certainty\n",
    "        axes_gif['certainty'].plot(np.arange(n_steps), these_certainties[1], 'k-', linewidth=2)\n",
    "        axes_gif['certainty'].set_xlim([0, n_steps-1])\n",
    "        axes_gif['certainty'].axvline(x=stepi, color='black', linewidth=1, alpha=0.5)\n",
    "        axes_gif['certainty'].set_xticklabels([])\n",
    "        axes_gif['certainty'].set_yticklabels([])\n",
    "        axes_gif['certainty'].grid(False)\n",
    "        for spine in axes_gif['certainty'].spines.values():\n",
    "            spine.set_visible(False)\n",
    "\n",
    "        # Neuron Traces\n",
    "        for neuroni in range(n_neurons_to_visualise):\n",
    "            ax = axes_gif[f'trace_{neuroni}']\n",
    "            pre_activation = these_pre_acts[:, neuroni]\n",
    "            post_activation = these_post_acts[:, neuroni]\n",
    "            ax_pre = ax.twinx()\n",
    "\n",
    "            ax_pre.plot(np.arange(n_steps), pre_activation, color='grey', linestyle='--', linewidth=1, alpha=0.4)\n",
    "            color = 'blue' if neuroni % 2 else 'red'\n",
    "            ax.plot(np.arange(n_steps), post_activation, color=color, linewidth=2, alpha=1.0)\n",
    "\n",
    "            ax.set_xlim([0, n_steps-1])\n",
    "            ax_pre.set_xlim([0, n_steps-1])\n",
    "            ax.set_ylim([np.min(post_activation), np.max(post_activation)])\n",
    "            ax_pre.set_ylim([np.min(pre_activation), np.max(pre_activation)])\n",
    "\n",
    "            ax.axvline(x=stepi, color='black', linewidth=1, alpha=0.5)\n",
    "            ax.set_xticklabels([])\n",
    "            ax.set_yticklabels([])\n",
    "            ax.grid(False)\n",
    "            ax_pre.set_xticklabels([])\n",
    "            ax_pre.set_yticklabels([])\n",
    "            ax_pre.grid(False)\n",
    "\n",
    "            for spine in ax.spines.values():\n",
    "                spine.set_visible(False)\n",
    "            for spine in ax_pre.spines.values():\n",
    "                spine.set_visible(False)\n",
    "\n",
    "        # Input image\n",
    "        this_image = these_inputs[0]\n",
    "        this_image = (this_image - this_image.min()) / (this_image.max() - this_image.min() + 1e-8)\n",
    "        axes_gif['img_data'].set_title('Input Image')\n",
    "        axes_gif['img_data'].imshow(this_image, cmap='binary', vmin=0, vmax=1)\n",
    "        axes_gif['img_data'].axis('off')\n",
    "\n",
    "        # Attention\n",
    "        this_input_gate = these_attention_weights[stepi]\n",
    "        gate_min, gate_max = np.nanmin(this_input_gate), np.nanmax(this_input_gate)\n",
    "        if not np.isclose(gate_min, gate_max):\n",
    "            normalized_gate = (this_input_gate - gate_min) / (gate_max - gate_min + 1e-8)\n",
    "        else:\n",
    "            normalized_gate = np.zeros_like(this_input_gate)\n",
    "        attention_weights_heCTMap = heCTMap_cmap(normalized_gate)[:,:,:3]\n",
    "\n",
    "        axes_gif['attention'].imshow(attention_weights_heCTMap, vmin=0, vmax=1)\n",
    "        axes_gif['attention'].axis('off')\n",
    "        axes_gif['attention'].set_title('Attention')\n",
    "\n",
    "        fig_gif.tight_layout()\n",
    "        canvas = fig_gif.canvas\n",
    "        canvas.draw()\n",
    "        image_numpy = np.frombuffer(canvas.buffer_rgba(), dtype='uint8')\n",
    "        image_numpy = image_numpy.reshape(*reversed(canvas.get_width_height()), 4)[:, :, :3]\n",
    "        frames.append(image_numpy)\n",
    "        plt.close(fig_gif)\n",
    "\n",
    "\n",
    "    mediapy.show_video(frames, width=400, codec=\"gif\")\n",
    "    imageio.mimsave(filename, frames, fps=5, loop=100)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "20040db6",
   "metadata": {},
   "source": [
    "The top row of the gif shows the input image, the attention weights and the models predictions.\n",
    "\n",
    "The second plot, in black, shows the models certainty over time.\n",
    "\n",
    "The red and blue lines correspond to the post-activations of different neurons, with the corresponding pre-activation shown in gray."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "20040db6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table class=\"show_videos\" style=\"border-spacing:0px;\"><tr><td style=\"padding:1px;\"><img width=\"400\" height=\"490\" style=\"image-rendering:auto; object-fit:cover;\" src=\"\"/></td></tr></table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "logdir = f\"mnist_logs\"\n",
    "if not os.path.exists(logdir):\n",
    "    os.makedirs(logdir)\n",
    "\n",
    "model.eval()\n",
    "with torch.inference_mode():\n",
    "    inputs, targets = next(iter(testloader))\n",
    "    inputs = inputs.to(device)\n",
    "\n",
    "    predictions, certainties, (synch_out_tracking, synch_action_tracking), \\\n",
    "    pre_activations_tracking, post_activations_tracking, attention = model(inputs, track=True)\n",
    "\n",
    "    make_gif(\n",
    "        predictions.detach().cpu().numpy(),\n",
    "        certainties.detach().cpu().numpy(),\n",
    "        targets.detach().cpu().numpy(),\n",
    "        pre_activations_tracking,\n",
    "        post_activations_tracking,\n",
    "        attention,\n",
    "        inputs.detach().cpu().numpy(),\n",
    "        f\"{logdir}/prediction.gif\"\n",
    "    )"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
